<!doctype html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>Document</title>
	</head>

	<body>
		<style>
			* {
				margin: 0;
				padding: 0;
			}

			.outer {
				width: 1000px;
				height: 550px;
				overflow: auto;
				margin: 100px auto;
				border: 1px solid teal;
			}

			.item {
				height: 50px;
				line-height: 50px;
				background: #f8f8f8;
				margin-bottom: 10px;
			}
		</style>
		<div class="outer">
			<!-- container 负责滚动 -->
			<div class="container">
				<!-- scroll 负责内容和内容偏移 -->
				<div class="scroller"></div>
			</div>
		</div>
		<script>
			let startIndex = 0;
			const total = 100000;
			const list = Array(total)
				.fill(0)
				.map((item, index) => index + 1);
			const itemHeight = 50;
			const outer = document.querySelector('.outer');
			const container = document.querySelector('.container');
			const scroller = document.querySelector('.scroller');
			const limit = parseInt(document.querySelector('.outer').offsetHeight / itemHeight);
			container.style.height = total * itemHeight + 'px';

			render();

			outer.addEventListener('scroll', scrollFn);

			function scrollFn() {
				const scrollTop = outer.scrollTop;
				currentIndex = parseInt(scrollTop / itemHeight);
				if (currentIndex != startIndex) {
					startIndex = currentIndex;
					render();
				}
			}

			// 设置可视区域数据
			function render() {
				let fragment = document.createDocumentFragment(); // 创建文档碎片
				let showList = list.slice(startIndex, startIndex + limit); // 取出要渲染的数据
				for (let i = 0; i < showList.length; i++) {
					let el = document.createElement('div');
					el.className = 'item';
					el.innerText = `列表项${showList[i]}`;
					fragment.appendChild(el);
				}
				scroller.innerHTML = '';
				scroller.appendChild(fragment);
				scroller.style.transform = 'translateY(' + startIndex * itemHeight + 'px)';
			}
		</script>
	</body>
</html>
